﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Fast.Framework.Extensions
{

    /// <summary>
    /// 类型扩展类
    /// </summary>
    public static class TypeExtensions
    {

        /// <summary>
        /// 获取表名称
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static string GetTableName(this Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            if (type.IsDefined(typeof(TableAttribute)))
            {
                return type.GetCustomAttribute<TableAttribute>().Name;
            }
            return type.Name;
        }

        /// <summary>
        /// 获取列名称
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static List<string> GetColumnName(this Type type)
        {
            var nameList = new List<string>();
            var propertyInfos = type.GetProperties().Where(w => !w.IsDefined(typeof(KeyAttribute)) && !w.IsDefined(typeof(NotMappedAttribute)))
                .Where(w => !w.PropertyType.IsClass || w.PropertyType.Equals(typeof(string)));
            foreach (var propertyInfo in propertyInfos)
            {
                if (propertyInfo.IsDefined(typeof(ColumnAttribute)))
                {
                    nameList.Add(propertyInfo.GetCustomAttribute<ColumnAttribute>().Name);
                }
                else
                {
                    nameList.Add(propertyInfo.Name);
                }
            }
            return nameList;
        }

        /// <summary>
        /// 获取主键
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static List<string> GetPrimaryKey(this Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }
            var list = type.GetProperties().Where(w => w.IsDefined(typeof(KeyAttribute))).
                Select(s => s.IsDefined(typeof(ColumnAttribute)) ? s.GetCustomAttribute<ColumnAttribute>().Name : s.Name).ToList();
            //if (list.Count == 0)
            //{
            //    throw new Exception("未获取到主键名称，请标记KeyAttribute");
            //}
            return list;
        }

        /// <summary>
        /// 获取类型默认值
        /// </summary>
        /// <param name="types">类型</param>
        /// <returns></returns>
        public static List<object> GetTypeDefaultValue(this Type[] types)
        {
            var values = new List<object>();
            foreach (var type in types)
            {
                values.Add(type.GetTypeDefaultValue());
            }
            return values;
        }

        /// <summary>
        /// 获取类型默认值
        /// </summary>
        /// <param name="types">类型</param>
        /// <returns></returns>
        public static List<object> GetTypeDefaultValue(this List<Type> types)
        {
            var values = new List<object>();
            foreach (var type in types)
            {
                values.Add(type.GetTypeDefaultValue());
            }
            return values;
        }

        /// <summary>
        /// 获取类型默认值
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static object GetTypeDefaultValue(this Type type)
        {
            if (type.Equals(typeof(DBNull)))
            {
                return DBNull.Value;
            }
            if (type == null || type.IsClass && !type.Equals(typeof(string)))
            {
                return null;
            }
            else if (type.Equals(typeof(DateTime)))
            {
                return default(DateTime);
            }
            else if (type.IsValueType)
            {
                return 0;
            }
            return null;
        }

    }
}
